#include <GameManager.h>
#include <GameState.h>

template<> GameManager* Ogre::Singleton<GameManager>::ms_Singleton = 0;

GameManager::GameManager()
{
  _root = NULL;
  _sceneMgr = NULL;
  _renderWindow = NULL;
}

GameManager::~GameManager()
{

  while (!_states.empty())
  {
    _states.top()->exit();
    _states.pop();
  }

  if (_inputMgr) delete _inputMgr;
  if (_camera) _sceneMgr->destroyCamera(_camera);
  if (_sceneMgr) _root->destroySceneManager(_sceneMgr);
  if (_renderWindow) delete _renderWindow;
}

void GameManager::start(GameState* state)
{
  _root = Ogre::Root::getSingletonPtr();

  // Creación del gestor de escena
  _sceneMgr = _root->createSceneManager(Ogre::ST_GENERIC, "SceneManager");

  loadResources();

  if (!configure()) return;	

  _inputMgr = new InputManager;
  _inputMgr->initialise(_renderWindow);

  // Registro como key y mouse listener...
  _inputMgr->addKeyListener(this, "GameManager");
  _inputMgr->addMouseListener(this, "GameManager");

  // El GameManager es un FrameListener.
  _root->addFrameListener(this);

  // Creación de la camara
  _camera = _sceneMgr->createCamera("MainCamera");

  // Transición al estado inicial.
  changeState(state);

  // Bucle de rendering.
  _root->startRendering();
}

void GameManager::changeState(GameState* state)
{
  // Limpieza del estado actual.
  if (!_states.empty())
  {
    // exit() sobre el último estado.
    _states.top()->exit();

    // Elimina el último estado.
    _states.pop();
  }

  // Transición al nuevo estado.
  _states.push(state);

  // enter() sobre el nuevo estado.
  _states.top()->enter();
}

void GameManager::pushState(GameState* state)
{
  // Pausa del estado actual.
  if (!_states.empty())
    _states.top()->pause();

  // Transición al nuevo estado.
  _states.push(state);
  // enter() sobre el nuevo estado.
  _states.top()->enter();
}

void GameManager::popState()
{
  // Limpieza del estado actual.
  if (!_states.empty())
  {
    _states.top()->exit();
    _states.pop();
  }

  // Vuelta al estado anterior.
  if (!_states.empty())
    _states.top()->resume();
}

void GameManager::loadResources()
{
  Ogre::ConfigFile cf;
  cf.load("resources.cfg");

  Ogre::ConfigFile::SectionIterator sI = cf.getSectionIterator();
  Ogre::String sectionstr, typestr, datastr;

  while (sI.hasMoreElements())
  {
    sectionstr = sI.peekNextKey();
    Ogre::ConfigFile::SettingsMultiMap *settings = sI.getNext();
    Ogre::ConfigFile::SettingsMultiMap::iterator i;

    for (i = settings->begin(); i != settings->end(); ++i)
    {
      typestr = i->first;    datastr = i->second;
      Ogre::ResourceGroupManager::getSingleton().addResourceLocation
        (datastr, typestr, sectionstr);	
    }

  }
}

bool GameManager::configure()
{
  if (!_root->restoreConfig())
  {
    if (!_root->showConfigDialog())
      return false;
  }

  _renderWindow = _root->initialise(true, "Espeis Invaders");

  Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

  return true;
}

GameManager* GameManager::getSingletonPtr ()
{
  return ms_Singleton;
}

GameManager& GameManager::getSingleton ()
{  
  assert(ms_Singleton);
  return *ms_Singleton;
}

// Las siguientes funciones miembro delegan
// el evento en el estado actual.

bool GameManager::frameStarted(const Ogre::FrameEvent& evt)
{
  _inputMgr->capture();
  return _states.top()->frameStarted(evt);
}

bool GameManager::frameEnded(const Ogre::FrameEvent& evt)
{
  return _states.top()->frameEnded(evt);
}

bool GameManager::keyPressed(const OIS::KeyEvent& e)
{
  _states.top()->keyPressed(e);
  return true;
}

bool GameManager::keyReleased(const OIS::KeyEvent& e)
{
  _states.top()->keyReleased(e);
  return true;
}

bool GameManager::mouseMoved(const OIS::MouseEvent& e)
{
  _states.top()->mouseMoved(e);
  return true;
}

bool GameManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
  _states.top()->mousePressed(e, id);
  return true;
}

bool GameManager::mouseReleased(const OIS::MouseEvent& e, OIS::MouseButtonID id)
{
  _states.top()->mouseReleased(e, id);
  return true;
}
